#include "imagebox.h"

#include <assert.h>

ATOM ImageBox::_wndClass = NULL;

ImageBox::ImageBox()
{
	_dib = NULL;
	_hWnd = NULL;
	_scale = 1.0;
}

ImageBox::~ImageBox()
{
	if( IsWindow( _hWnd ) )
	{
		//Detach the instance from this window and destroy the window.
		SetWindowLongPtr( _hWnd, GWLP_USERDATA, NULL );
		DestroyWindow( _hWnd );
	}
}

bool ImageBox::create( HWND hWndParent, HINSTANCE hInstance )
{
	if( registerWndClass( hInstance ) == false )
	{
		return false;
	}

	_hWnd = CreateWindowEx(
		WS_EX_CLIENTEDGE, //dwExStyle
		(LPCWSTR) _wndClass, //lpClassName
		L"", //lpWindowName
		WS_CHILD, //dwStyle
		CW_USEDEFAULT, //X
		CW_USEDEFAULT, //Y
		200, //nWidth
		150, //nHeight
		hWndParent, //hWndParent
		NULL, //hMenu
		hInstance, //hInstance
		NULL //lpParam
		);
	if( _hWnd == NULL )
	{
		return false;
	}

	//Store a pointer to this ImageBox instance with the window.
	SetWindowLongPtr( _hWnd, GWLP_USERDATA, (LONG_PTR) this );
	UpdateWindow( _hWnd );
	return true;
}

DIB* ImageBox::dib()
{
	return _dib;
}

void ImageBox::setDib( DIB *dib )
{
	_dib = dib;

	//Repaint the window.
	InvalidateRect( _hWnd, NULL, TRUE );
}

BOOL ImageBox::setPosition( RECT rect, BOOL repaint )
{
	return MoveWindow(
		_hWnd,
		rect.left,
		rect.top,
		rect.right - rect.left,
		rect.bottom - rect.top,
		repaint
		);
}

void ImageBox::show( int nCmdShow )
{
	ShowWindow( _hWnd, nCmdShow );
}

POINT ImageBox::position() const
{
	return _position;
}

void ImageBox::setPosition( POINT pos )
{
	_position = pos;

	//Repaint the window.
	InvalidateRect( _hWnd, NULL, TRUE );
}

void ImageBox::center()
{
	if( _dib )
	{
		POINT pos;
		RECT clientRect;
		SIZE srcSize, destSize;
		srcSize = _dib->size();
		destSize.cx = (LONG) ( (double) srcSize.cx * _scale );
		destSize.cy = (LONG) ( (double) srcSize.cy * _scale );

		//Get the (client) size of the window.
		GetClientRect( _hWnd, &clientRect );

		pos.x = ( clientRect.right - clientRect.left ) / 2 - destSize.cx / 2;
		pos.y = ( clientRect.bottom - clientRect.top ) / 2 - destSize.cy / 2;

		setPosition( pos );
	}
}

double ImageBox::scale()
{
	return _scale;
}

void ImageBox::setScale( double scale )
{
	//The scale may not be negative, nor zero.
	assert( scale > 0.0 );

	_scale = scale;
}

LRESULT ImageBox::handleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	switch( uMsg )
	{
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hDC = BeginPaint( _hWnd, &ps );
			if( _dib )
			{
				SIZE srcSize, destSize;
				srcSize = _dib->size();
				destSize.cx = (LONG) ( (double) srcSize.cx * _scale );
				destSize.cy = (LONG) ( (double) srcSize.cy * _scale );

				//Paint the image. This function will resize the image if the
				//scale is not equal to 1.0.
				StretchDIBits(
					hDC, //hdc
					_position.x, //xDest
					_position.y, //yDest
					destSize.cx, //destWidth
					destSize.cy, //destHeight
					0, //xSrc
					0, //ySrc
					srcSize.cx, //srcWidth
					srcSize.cy, //srcHeight
					_dib->data(), //lpBits
					&*_dib->format(), //lpbmi
					DIB_RGB_COLORS, //iUsage
					SRCCOPY //rop
					);
			}
			EndPaint( _hWnd, &ps );
		}
		break;
	case WM_SIZE:
		//Keep the image in the middle while resizing the window.
		center();
	default:
		break;
	}
	//Call the default message handler.
	return DefWindowProc( _hWnd, uMsg, wParam, lParam );
}

HWND ImageBox::hWnd() const
{
	return _hWnd;
}

bool ImageBox::registerWndClass( HINSTANCE hInstance )
{
	if( _wndClass == NULL )
	{
		WNDCLASSEX wc;

		wc.cbSize        = sizeof( WNDCLASSEX );
		wc.style         = 0;
		wc.lpfnWndProc   = &Window::ooDispatcher;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = hInstance;
		wc.hIcon         = LoadIcon( NULL, IDI_APPLICATION );
		wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
		wc.hbrBackground = (HBRUSH) ( COLOR_WINDOW + 1 );
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = L"ImageBox";
		wc.hIconSm       = LoadIcon( NULL, IDI_APPLICATION );

		_wndClass = RegisterClassEx( &wc );
		if( _wndClass == NULL )
		{
			//Registration of window class failed.
			return false;
		}
	}
	return true;
}
